/*
 * This file is part of aKoustiK.

 * aKoustiK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * aKoustiK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with aKoustiK.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef PLAYER_H
#define PLAYER_H

#include <QtCore/QList>
#include <QtCore/QObject>
#include <QtCore/QSet>

#include <Phonon/AudioOutput>
#include <Phonon/MediaObject>

#include <playlist.h>

/**
  Player engine. It encapsulates all work with any backend KDE will use.
  Currently Phonon is used.
  */
class Player : public QObject {
    Q_OBJECT

public:

    // constructors/destructors:
    Player(QObject* parent);
    ~Player();

    bool shuffle();
    bool repeat();

    // VolumeWidget:
    int volume();
    // SeekWidget:
    qint64 totalTime();
    qint64 time();
    /** Method for ItemDelegate to indicate current item in playlist. */
    int current() const;
    /**
     Method for ItemDelegate to indicate if this item should be grey.
     In shuffle mode greySet is holding all grey items. Otherwise all items
     higher in playlist are grey.
     */
    bool isGrey(int index) const;

private:

    // fields:
    bool mRepeat;
    bool mShuffle;
    bool mMute;
    int mVolume;
    Playlist* playlist;
    Phonon::AudioOutput* mAudioOutput;
    Phonon::MediaObject* mMediaObject;
    /** Pointer to current Item, is set by prev-next methods. */
    Item currentItem;
    /** Index of currentItem in playlist. Used mostly by prev-next methods and to indicate current item on UI. */
    int currentIndex;

    // history and grey handling:
    /** History of playback, to move backward on user request and to help handle greySet. */
    QList<Item*> historyList;
    /** Set of items that should be marked grey in playlist and will not be played until all black items will be played. */
    QSet<Item*> greySet;
    /** Taking last item from history, removing it from hisotyr and greySet. */
    Item* historyTakeLast();
    /**
      Must perform some adding operation when moving to next item, including adding to history and greySet.
      */
    void historyAppend(Item* item);
    /** When removing item from playlist - it must be removed from hisotyr and greySet too. */
    void historyRemove(Item* item);
    /**
      Method to clean historyList and greySet.
      In repeat mode half of playlist should stay in greySet, full size of playlist should be used otherwise.
      */
    void historyCleanup();

    // methods:
    /**
      Method to change currentIndex and currentItem to next ones when track ends or user requested.
      There are 2 flags we should check: repeat and shuffle.
      If shuffle - we should generate next random integer, take item from playlist, check if it's still in grey list and play it if not.
      If shuffle and not repeat - we should check the size of grey list and stop if it's the same as size of playlist.
      If !shuffle - we should increase currentIndex. If it will exceed size of playlist - we should stop, otherwise - set current index
      to 0 and start from beginning.

      Returns false if player should stop after current track.
      */
    bool moveToNext();
    /** Method to generate random int */
    int generateRandom();

signals:
    // VolumeWidget:
    void volumeChanged(int);
    // SeekWidget:
    void seekableChanged(bool isSeekable);
    void totalTimeChanged(qint64 newTotalTime);
    void tick(qint64 time);
    void sourceChanged();
    /** This signal must be emited every time currentIndex is changed. -1 will be passed if there is no valid old or new item. */
    void currentItemChanged(int newItem, int oldItem);

public slots:
    /**
      Move playback to previous played Item.
      */
    void previous();
    /**
      Play method should start playing current Item.
      If there is no current item and shuffle flag is on - should generate
      random index of item and play it. If no current item and !shuffle -
      take item 0.
      If current item is already playing - should start it from beginning.
      */
    void play();
    /**
      UI can send signal to play item at certain index in playlist.
      Basic behaviour is the same as play() method, but we should use Item
      at specified index.
      */
    void play(int index);
    void pause();
    void stop();
    /**
      Move playback to next item.
      If shuffle is on - generate random index, check if it's in grey list and play it if not.
      If shuffle is off - increase current index and take item at that position.
      */
    void next();
    void mute(bool mute);
    void repeat(bool repeat);
    void shuffle(bool shuffle);
    void setVolume(int volume);
    void seek(qint64 time);

private slots:
    void outputVolumeChanged(qreal value);
    void sourceSeekableChanged(bool isSeekable);
    void sourceTotalTimeChanged(qint64 newTotalTime);
    void sourceTick(qint64 time);
    void sourceSourceChanged(const Phonon::MediaSource& source);
    void sourceStateChanged(Phonon::State newstate, Phonon::State oldstate);
    /**
      We are watching when Phonon ends playback and we should enqueue next item.
      Next item should be selected in the same way as next() does it.
      */
    void aboutToFinish();
    /**
      Slot connected to any item removing methods of Playlist.
      1. It will shift current index if removed item is higher in list.
      2. It will remove item from history and greySet.
      3. It will invalidate current index and current item.
      */
    void playlistItemRemoving(int itemIndex, Item* item);

};

#endif
